// 实现这个项目的构建任务
const { src, dest, parallel, series, watch } = require('gulp');

const del = require('del')
const browserSync = require('browser-sync')
const loadPlugins = require('gulp-load-plugins')

const plugins = loadPlugins()
const bs = browserSync.create()

const data = {
    menus: [
        {
            name: 'Home',
            icon: 'aperture',
            link: 'index.html'
        },
        {
            name: 'Features',
            link: 'features.html'
        },
        {
            name: 'About',
            link: 'about.html'
        },
        {
            name: 'Contact',
            link: '#',
            children: [
                {
                    name: 'Twitter',
                    link: 'https://twitter.com/w_zce'
                },
                {
                    name: 'About',
                    link: 'https://weibo.com/zceme'
                },
                {
                    name: 'divider'
                },
                {
                    name: 'About',
                    link: 'https://github.com/zce'
                }
            ]
        }
    ],
    pkg: require('./package.json'),
    date: new Date()
}

/**
 * styles：将Scss文件编译成css并且导入到dist的方法
 *  使用src获取到源目标的文件流并传入配置对象设置为 base: 'src'
 * 获取目标的文件流
 *  调用pipe方法再传入sass模板对文件流进行编译并设置sass配置对象为
 * outputStyle: 'expanded';意思编译之后的css是完全展开的
 *  最后调用pipe方法将编译好的文件输入到dist
 */
const styles = () => {
    return src('src/assets/styles/*.scss', { base: 'src' })
        .pipe(plugins.sass({ outputStyle: 'expanded' }))
        .pipe(dest('temp'))
        .pipe(bs.reload({ stream: true }));
};

/**
 * script: 将Js文件打包至dist
 *  gulp-babel并不能直接转换代码，需要手动安装babel/core babel/preset-env
 *  babeld/core是babel的核心但是babel需要插件才能完成对js代码的编译，preset-env就是这样的插件
 *  在babel中传入配置对象 {presets:['@babel/preset-env']}，表述项目按照preset-env的方式去编译
 */
const script = () => {
    return src('src/assets/scripts/*.js', { base: 'src' })
        .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
        .pipe(dest('temp'))
        .pipe(bs.reload({ stream: true }));
}

/**
 * page: 编译html
 * 为了不和布局页冲突 这里的page打包src下的html文件
 */
const page = () => {
    return src('src/*.html').pipe(plugins.swig({ data, defaults: { cache: false } }))
        .pipe(dest('temp'))
        .pipe(bs.reload({ stream: true }));
}

// image:压缩图片输出到dist
const image = () => {
    return src('src/assets/images/**', { base: 'src' })
        .pipe(plugins.imagemin())
        .pipe(dest('dist'))
        .pipe(bs.reload({ stream: true }));
}
// font: 压缩字体输出到dist
const font = () => {
    return src('src/assets/fonts/**', { base: 'src' })
        .pipe(plugins.imagemin())
        .pipe(dest('dist'))
        .pipe(bs.reload({ stream: true }));
}
// extra: 此方法将public直接导入到dist中
const extra = () => {
    return src('public/**', { base: 'public' })
        .pipe(dest('dist'));
}
// clean: 此方法用于清除旧的dist
const clean = () => {
    return del(['dist', 'temp'])
}

/**
 * serve: 热更新静态资源服务器
 * 页面中依赖使用了node_module要将这个地址也进行重定向，使预览能够看见页面效果；
 * baseDir: 指定根目录位置
 * files: 文件监听的目标
 * routers: 重新指向
 */
const serve = () => {
    watch('src/assets/styles/*.scss', styles);
    watch('src/assets/script/*.js', script);
    watch('src/*.html', page);
    watch(['src/assets/images/**',
        'src/assets/fonts/**',
        'pubilc/**'], bs.reload);
    bs.init({
        server: {
            baseDir: ['temp', 'src', 'public'],
            files: 'dist/**',
            routes: { '/node_modules': 'node_modules' }
        }
    })
}

/**
 * useref：对文件依赖进行处理
 *  这里的目标源：dist
 *  由于操作dist文件中的*.html所以useref放在后面执行
 *  操作完成后要继续放回dist
 */
const useref = () => {
    return src('temp/*.html', { base: 'temp' })
        .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
        // html js css
        .pipe(plugins.if(/\.js$/, plugins.uglify()))
        .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
        .pipe(plugins.if(/\.html$/, plugins.htmlmin({
            collapseWhitespace: true,
            minifyCSS: true,
            minifyJS: true
        })))
        .pipe(dest('dist'))
}
/**
 * buildTask: 把多个任务组合
 * 实现一条命令完成构建
 */
// const buildTask = parallel(page, styles, script, image, font, extra);
// const build = series(buildTask, useref, serve)

// 组合编译任务
const compile = parallel(styles, script, page)
const build = series(
    clean,
    parallel(
        series(compile, useref),
        image,
        font,
        extra
    ),
    serve
)

module.exports = {
    build
}